OAuth2

1
2
3
4
5
6
7
8
   ____                    _    _       ___  
/ __ \ /\ | | | | |__ \
| | | | / \ _ _ | |_ | |__ ) |
| | | | / /\ \ | | | || __|| '_ \ / /
| |__| | / ____ \ | |_| || |_ | | | | / /_
\____/ /_/ \_\ \__,_| \__||_| |_| |____|

这是<<session,cookie,token>>进阶版.

为什么说是”进阶版”? 以为他们都是认证机制

是什么: 开放授权,开发认证中心

四种方式:

一. 到底 OAuth 是什么?

认证 Authentication VS 授权 Authorization

看授权模式图之前,先区别下这两个概念。

  • 认证就是我要输入帐号和密码来证明我是我
  • 授权就是并非通过帐号和密码来把我的东西借给其他人
  • 这其中的关键就是,是否需要输入帐号密码。记住,OAuth 不需要输入帐号和密码,你要做的只是授权。
    下面这张图清晰的说明了,认证和授权。


二. 授权模式

1. 授权码模式 Authorization Code

  • 授权码模式是最常见常用的模式,我们所熟悉的微博,QQ 等都是这种模式。
  • 另外也是最繁琐的一种方式,如果弄懂了这个相信接下来的三种类型都会迎刃而解。
  • 这种模式和其他最大的区别就在于是否有授权码这个步骤。

1.1 图解

1.2 授权请求 Authorization Request

1
2
3
4
5
6
7
8
GET {认证终点}
?response_type=code // 必选项
&client_id={客户端的ID} // 必选项
&redirect_uri={重定向URI} // 可选项
&scope={申请的权限范围} // 可选项
&state={任意值} // 推荐
HTTP/1.1
HOST: {认证服务器}

1.3 授权响应 Authorization Response

1
2
3
4
HTTP/1.1 302 Found
Location: {重定向URI}
?code={授权码} // 必填
&state={任意文字} // 如果授权请求中包含 state的话那就是必填

1.4 令牌请求 Access Token Request

1
2
3
4
5
6
7
8
POST {令牌终点} HTTP/1.1
Host: {认证服务器}
Content-Type: application/x-www-form-urlencoded

grant_type=authorization_code // 必填
&code={授权码} // 必填 必须是认证服务器响应给的授权码
&redirect_uri={重定向URI} // 如果授权请求中包含 redirect_uri 那就是必填
&code_verifier={验证码} // 如果授权请求中包含 code_challenge 那就是必填

根据具体情况有可能是向客户端服务器进行请求,这时候请加上 Basic 认证(Authorization 头部)或者是 参数 client_id & client_secret

1.5 令牌响应 Access Token Response

1
2
3
4
5
6
7
8
9
10
11
12
HTTP/1.1 200 OK
Content-Type: application/json;charset=UTF-8
Cache-Control: no-store
Pragma: no-cache

{
"access_token":"{访问令牌}", // 必填
"token_type":"{令牌类型}", // 必填
"expires_in":{过期时间}, // 任意
"refresh_token":"{刷新令牌}", // 任意
"scope":"{授权范围}" // 如果请求和响应的授权范围不一致就必填
}

2. 简化模式 Implicit

  • 简化模式,顾名思义,就是简化了的模式。
  • 简化的就是授权码这个步骤。

    2.1 图解

2.2 授权请求 Authorization Request

1
2
3
4
5
6
7
8
GET {授权终点}
?response_type=token // 必填
&client_id={客户端ID} // 必填
&redirect_uri={重定向URI} // 可选。授权成功后的重定向地址
&scope={授权范围} // 任意
&state={任意文字} // 推荐
HTTP/1.1
HOST: {认证服务器}

2.3 授权响应 Authorization Response

1
2
3
4
5
6
7
HTTP/1.1 302 Found
Location: {重定向URI}
#access_token={令牌码} // 必填
&token_type={令牌类型} // 必填
&expires_in={过期时间} // 任意
&state={任意文字} // 如果授权请求中包含 state 那就是必填
&scope={授权范围} // 如果请求和响应的授权范围不一致就必填

3. 密码模式 Resource Owner Password Credentials

  • 密码模式其实就是进一步再去简化了简化模式。
  • 不仅仅没有了授权码模式下的授权码,也没了简化模式下的授权请求。
  • 直接就请求了令牌码。

3.1 图解

3.2 令牌请求 Access Token Request

1
2
3
4
5
6
7
8
POST {令牌终点} HTTP/1.1
Host: {认证服务器}
Content-Type: application/x-www-form-urlencoded

grant_type=password // 必填
&username={用户ID} // 必填
&password={密码} // 必填
&scope={授权范围} // 任意

根据具体情况有可能是向客户端服务器进行请求,这时候请加上 Basic 认证(Authorization 头部)或者是 参数 client_id & client_secret

3.3 令牌响应 Access Token Response

1
2
3
4
5
6
7
8
9
10
11
12
HTTP/1.1 200 OK
Content-Type: application/json;charset=UTF-8
Cache-Control: no-store
Pragma: no-cache

{
"access_token":"{访问令牌}", // 必填
"token_type":"{令牌类型}", // 必填
"expires_in":{过期时间}, // 任意
"refresh_token":"{刷新令牌}", // 任意
"scope":"{授权范围}" // 如果请求和响应的授权范围不一致就必填
}

4. 客户端模式 Client Credentials

  • 客户端模式可是最简化的了。
  • 什么都不问,直接请求!简单粗暴给我令牌!

4.1 图解

4.2 令牌请求 Access Token Request

1
2
3
4
5
6
7
POST {令牌终点} HTTP/1.1
Host: {认证服务器}
Authorization: Basic {客户端模式}
Content-Type: application/x-www-form-urlencoded

grant_type=client_credentials // 必填
&scope={授权范围} // 任意

4.3 令牌响应 Access Token Response

1
2
3
4
5
6
7
8
9
10
11
HTTP/1.1 200 OK
Content-Type: application/json;charset=UTF-8
Cache-Control: no-store
Pragma: no-cache

{
"access_token":"{访问令牌}", // 必填
"token_type":"{令牌类型}", // 必填
"expires_in":{过期时间}, // 任意
"scope":"{授权范围}" // 如果请求和响应的授权范围不一致就必填
}

5. 刷新令牌 Refresh Token

5.1 图解

第三方已存在令牌码为前提进行更新令牌

5.2 令牌请求 Access Token Request

1
2
3
4
5
6
7
POST {令牌终点} HTTP/1.1
Host: {认证服务器}
Content-Type: application/x-www-form-urlencoded

grant_type=refresh_token // 必填
&refresh_token={刷新令牌} // 必填
&scope={授权范围} // 任意

根据具体情况有可能是向客户端服务器进行请求,这时候请加上 Basic 认证(Authorization 头)或者是 参数 client_id & client_secret

5.3 令牌响应 Access Token Response

1
2
3
4
5
6
7
8
9
10
11
12
HTTP/1.1 200 OK
Content-Type: application/json;charset=UTF-8
Cache-Control: no-store
Pragma: no-cache

{
"access_token":"{访问令牌}", // 必填
"token_type":"{令牌类型}", // 必填
"expires_in":{过期时间}, // 任意
"refresh_token":"{刷新令牌}", // 任意
"scope":"{授权范围}" // 如果请求和响应的授权范围不一致就必填
}

三. 总结

授权模式 授权终点 令牌终点
授权码模式 使用 使用
简化模式 使用 不使用
密码模式 不使用 使用
客户端模式 不使用 使用
刷新令牌 不使用 使用

其实授权终点就是授权请求和响应
令牌终点就是令牌的请求和响应

感谢您的阅读!




如何获取这么多图片的base64?

注意: 这都是试验性质的代码. 主要测试reduce顺便把base64下载下来.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
import cn.hutool.core.codec.Base64;
import cn.hutool.core.io.FileUtil;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import lombok.extern.slf4j.Slf4j;
import lombok.val;
import lombok.var;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.*;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
* @author : bingrun.chiu
* @description:
* @date: 2019/12/26 16:09
**/
@Slf4j
public class Mtihani {
public static void main(String... args) throws Exception {
List<String> list = Lists.newArrayList();

File file = new File("C:\\Users\\chiu\\Desktop\\oauth2.md");
InputStreamReader reader = new InputStreamReader(new FileInputStream(file));
BufferedReader bufferedReader = new BufferedReader(reader);
String lineText;
while ((lineText = bufferedReader.readLine()) != null) {
list.add(lineText);
}

List<String> alist = list.stream().filter(item -> item.contains(".png!large")).map(Mtihani::replaceIt).collect(Collectors.toList());

log.info("....." + "list = " + alist);
List<BufferedImage> imageList = Lists.newArrayList();

List<BufferedImage> reduceResult = alist.stream().parallel()
.reduce(imageList,
(x, y) -> {
var variable = getPng2(y);
x.add(variable);
return x;
},
(a, b) -> {
List<BufferedImage> bufferedImages = new ArrayList<>(a);
bufferedImages.addAll(b);
return bufferedImages;
}
);

log.info("....." + "size = " + reduceResult.size());
log.info("....." + "reduceResult = " + reduceResult);
log.info("========================================================================");
val blist = alist.stream().map(item -> {
Map<String, Object> map = Maps.newHashMap();
map.put(item, getBase64(getPng(item)));
return map;
}).collect(Collectors.toList());

log.info("....." + "size = " + blist.size());
log.info("....." + "blist = " + blist);
blist.forEach(item -> FileUtil.writeMap(item, new File("C:\\Users\\chiu\\Desktop\\Untitled-1.txt"), StandardCharsets.UTF_8, "\n", true));
}

public static BufferedImage getPng(String urlStr) {
BufferedImage image = null;
log.info("....." + "urlStr = " + urlStr);
try {
URL url = new URL(urlStr);
image = ImageIO.read(url);
} catch (IOException e) {
e.printStackTrace();
}
log.info("完成下载");

return image;
}


public static String getBase64(BufferedImage image) {
String head = "data:image/png;base64,";
String base64 = null;
try {
Integer width = image.getWidth();
Integer height = image.getHeight();
log.info("宽:" + width + " 高:" + height);

//输出流
ByteArrayOutputStream stream = new ByteArrayOutputStream();
ImageIO.write(image, "png", stream);
base64 = Base64.encode(stream.toByteArray());
log.info(head + base64);
} catch (IOException e) {
e.printStackTrace();
}
return head + base64;
}

public static String replaceIt(String item) {
item = item.trim().replace("![](", "").trim().replace(")", "");
item = item.replace("large", "").trim();
return item.replace("[", "").replace("]", "").replace("(", "").replace(")", "").replace("!", "");
}

public static BufferedImage getPng2(String urlStr) {
// List<BufferedImage> images = Lists.newArrayList();
log.info("....." + "urlStr = " + urlStr);
BufferedImage image = null;
try {
URL url = new URL(urlStr);
image = ImageIO.read(url);
} catch (IOException e) {
e.printStackTrace();
}
log.info("完成下载");
// images.add(image);
return image;
}
}